package com.fxu.role.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.fxu.framework.biz.util.LoginUtil;
import com.fxu.framework.core.base.Result;
import com.fxu.framework.core.base.ResultCode;
import com.fxu.framework.core.util.RSAUtil;
import com.fxu.role.entity.Admin;
import com.fxu.role.entity.AdminRole;
import com.fxu.role.entity.Menu;
import com.fxu.role.entity.RoleMenu;
import com.fxu.tpl.rest.ApiTplRestImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/admin")
@Api(tags = "管理员")
public class AdminController {

    @Autowired
    private ApiTplRestImpl apiRestImpl;

    @Value("${rsa.privateKey:}")
    private String passPrivateKey;
    @Value("${rsa.publicKey:}")
    private String passPublicKey;

    @GetMapping("/rsaKey/")
    @ApiOperation("加密公钥")
    public Result<String> rsaKey() {
        return Result.ok(passPublicKey);
    }

    @PostMapping("/login/")
    @ApiOperation("登录")
    public Result<Map<String, Object>> login(@Valid @RequestBody LoginReq req) {
        String password = RSAUtil.decrypt(passPrivateKey, req.getPassword());
        if (password == null) {
            return Result.error("密码解密错误!");
        }
        // 读取管理员信息和管理员菜单
        List<Menu> menuList = new ArrayList<>();
        Set<String> roleList = new HashSet<>();

        Admin admin = apiRestImpl.findLast(new Admin().query()
                .show(Admin::getId).show(Admin::getName).show(Admin::getPhone).show(Admin::getAvatar)
                .eq(Admin::getPhone, req.getPhone()).eq(Admin::getPassword, SecureUtil.md5(password)));
        if (null == admin) {
            return Result.error("找不到账号");
        }

        List<RoleMenu> roleMenus = null;
        // 超级用户
        if (req.getPhone().equals("13800000001") || req.getPhone().equals("13800000002")) {
            menuList = apiRestImpl.listBy(new Menu().query().show(Menu::getId).show(Menu::getParentId)
                    .show(Menu::getName).show(Menu::getIcon).show(Menu::getUrl).show(Menu::getRouter)
                    .show(Menu::getCompt).show(Menu::getHide));
        } else {
            List<AdminRole> adminRoles = apiRestImpl.listBy(new AdminRole().query()
                    .show(AdminRole::getId).show(AdminRole::getRoleId).eq(AdminRole::getAdminId, admin.getId()));
            if (adminRoles != null) {
                for (AdminRole adminRole : adminRoles) {
                    roleList.add(adminRole.getRoleId() + "");
                }
                List<Serializable> roleIds = adminRoles.stream().map(AdminRole::getRoleId).collect(Collectors.toList());
                roleMenus = apiRestImpl.listBy(new RoleMenu().query()
                        .show(RoleMenu::getId).show(RoleMenu::getRoleId).show(RoleMenu::getMenuId).show(RoleMenu::getPerms)
                        .in(RoleMenu::getRoleId, roleIds));
                if (roleMenus != null) {
                    List<Serializable> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
                    menuList = apiRestImpl.listBy(new Menu().query(menuIds).show(Menu::getId).show(Menu::getParentId)
                            .show(Menu::getName).show(Menu::getIcon).show(Menu::getUrl).show(Menu::getRouter)
                            .show(Menu::getCompt).show(Menu::getHide));
                }
            }
        }
        menuList = getMenuTreeList(menuList);
        String userKey = "TPL_ADMIN_" + admin.getId();
        Map<String, Object> back = cn.hutool.core.bean.BeanUtil.beanToMap(admin);
        LoginUtil.loginIn(userKey, admin.getPhone(), roleList, getPermList(menuList, roleMenus), menuList, back);
        back.put("menus", menuList);
        return Result.ok(back);
    }

    // ==> 对应 PermAuthAspect [RestFilter已经取消]
    private Set<String> getPermList(List<Menu> menuTreeList, List<RoleMenu> roleMenus) {
        Set<String> permList = new HashSet<>();
        if (menuTreeList == null || menuTreeList.size() <= 0) {
            return permList;
        }
        CollUtil.filterNew(menuTreeList, menu -> menu.getChildList() != null).forEach(menu -> {
            for (Menu child : menu.getChildList()) {
                // ==> 取消 RestFilter [permList.add(menu.getName() + ">" + child.getName());]
                String perms = "*"; // ==> 默认含有所有权限
                if (roleMenus != null) {
                    RoleMenu roleMenu = CollUtil.findOne(roleMenus, v -> v.getMenuId().equals(child.getId()));
                    if (roleMenu != null && !StrUtil.isEmpty(roleMenu.getPerms())) {
                        perms = roleMenu.getPerms();
                    }
                }
                permList.add(menu.getRouter() + "/" + child.getRouter() + ":" + perms);
            }
        });
        return permList;
    }

    private List<Menu> getMenuTreeList(List<Menu> menuList) {
        List<Menu> treeList = new ArrayList<>();
        if (menuList == null || menuList.size() <= 0) {
            return treeList;
        }
        CollUtil.filterNew(menuList, menu -> menu.getParentId() != null && menu.getParentId() == 0).forEach(menu -> {
            menu.setChildList(menuList.stream().filter(child -> child.getParentId() != null
                    && child.getParentId().equals(menu.getId())).collect(Collectors.toList()));
            treeList.add(menu);
        });
        return treeList;
    }

    @GetMapping("/info/")
    @ApiOperation("获取管理员信息")
    public Result<Map<String, Object>> info() {
        Map<String, Object> map = LoginUtil.getInfo(apiRestImpl.getToken());
        return null == map ? Result.error(ResultCode.NEED_LOGIN) : Result.ok(map);
    }

    @PostMapping("/logout/")
    @ApiOperation("登出")
    public Result<Boolean> logout() {
        return Result.ok(LoginUtil.loginOut(apiRestImpl.getToken()));
    }

    @PostMapping("/resetPswd/")
    @ApiOperation("修改密码")
    public Result<String> resetPswd(@Valid @RequestBody updatePasswordReq req) {
        Long userId = apiRestImpl.getUserIdByToken();
        Admin user = apiRestImpl.findLast(new Admin().query().onlyShowId().eq(Admin::getId, userId)
                .eq(Admin::getPassword, SecureUtil.md5(req.getOldPswd())));
        if (user == null) {
            return Result.error("您掉线或者旧密码错误!!");
        }
        apiRestImpl.saveOne(Admin.builder().id(userId).password(SecureUtil.md5(req.getNewPswd())).build());
        return Result.ok("成功");
    }

    @PostMapping("/saveProp/")
    @ApiOperation("修改属性")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "name", value = "名字", paramType = "query", dataTypeClass = String.class),
        @ApiImplicitParam(name = "avatar", value = "头像", paramType = "query", dataTypeClass = String.class),
    })
    public Result<String> saveProp(@RequestParam(value = "name", required = false) String name,
                                   @RequestParam(value = "avatar", required = false) String avatar) {
        if (StrUtil.isEmpty(name) && StrUtil.isEmpty(avatar)) {
            return Result.error("参数不能都为空!");
        }
        Long userId = apiRestImpl.getUserIdByToken();
        Admin admin = Admin.builder().id(userId).build();
        if (!StrUtil.isEmpty(avatar)) {
            admin.setAvatar(avatar);
        }
        if (!StrUtil.isEmpty(name)) {
            admin.setName(name);
        }
        apiRestImpl.saveOne(admin);
        return Result.ok("成功");
    }

    @Data
    static class updatePasswordReq {
        @NotBlank(message = "手机号必须填写")
        private String oldPswd;
        @NotBlank(message = "密码必须填写")
        private String newPswd;
    }

    @Data
    static class LoginReq {
        @NotBlank(message = "手机号必须填写")
        private String phone;
        @NotBlank(message = "密码必须填写")
        private String password;
    }
}